package com.scs.application.modules.dept.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrUnit;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.mapper.MatrUnitMapper;
import com.scs.application.modules.base.mapper.SupplierMapper;
import com.scs.application.modules.dept.dto.DeptAutoApplyKey;
import com.scs.application.modules.dept.entity.*;
import com.scs.application.modules.dept.mapper.PurchaseAutoMapper;
import com.scs.application.modules.dept.service.ApplyAutoService;
import com.scs.application.modules.dept.service.DemandItemService;
import com.scs.application.modules.dept.service.DemandService;
import com.scs.application.modules.dept.service.PurchaseAutoService;
import com.scs.application.modules.purchase.entity.Order;
import com.scs.application.modules.purchase.entity.OrderItem;
import com.scs.application.modules.purchase.enums.PoType;
import com.scs.application.modules.purchase.mapper.OrderItemMapper;
import com.scs.application.modules.purchase.mapper.OrderMapper;
import com.scs.application.modules.wm.dto.StockGroupWarehouseMatrDTO;
import com.scs.application.modules.wm.entity.Stock;
import com.scs.application.modules.wm.mapper.StockMapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
public class PurchaseAutoServiceImpl extends BaseServiceImpl<PurchaseAutoMapper, ApplyAuto> implements PurchaseAutoService {
    @Autowired
    private MatrMapper matrMapper;

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private DemandService demandService;
    @Autowired
    private DemandItemService demandItemService;
    @Autowired
    private SupplierMapper supplierMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private MatrUnitMapper matrUnitMapper;

    @Autowired
    private StockMapper stockMapper;

    @Autowired
    private ApplyAutoService applyAutoService;

    @Override
    public List<Order> toPurchase(List<ApplyAuto> applyAutos) {
        //先过滤作废的数据
        applyAutos = applyAutoService.list(Wrappers.<ApplyAuto>query().in("id", applyAutos.stream().map(ApplyAuto::getId).collect(Collectors.toList())));
        List<Matr> matrs = matrMapper.selectBatchIds(applyAutos.stream().map(item -> item.getMatrId()).collect(Collectors.toList()));
        // 依据供应商、需求科室
        Map<DeptAutoApplyKey, List<ApplyAuto>> groupApplyAuto = new HashMap<>();
        // key为耗材ID，value为耗材对象
        Map<String, Matr> matrMap = matrs.stream().collect(Collectors.toMap(matr -> matr.getId(), matr -> matr));

        for (ApplyAuto applyAuto : applyAutos) {
            String matrId = applyAuto.getMatrId();
            Matr matr = matrMap.get(matrId);

            if (matr == null) {
                // 明细中的耗材 在 耗材表中 不存在
                throw new BusinessException("品名：%s，品规：%s 在耗材基础数据中不存在，转换采购订单失败",
                        applyAuto.getMatrName(), applyAuto.getMatrSpec());
            }

            Boolean flagConsignment = matr.getFlagConsignment();
            Boolean flagOmoc = matr.getFlagOmoc();

            DeptAutoApplyKey deptAutoApplyKey = new DeptAutoApplyKey(matr.getSupplierId(), flagConsignment, flagOmoc, applyAuto.getDeptId(), applyAuto.getDeptName(), applyAuto.getApplyWarehouseId(), applyAuto.getApplyWarehouseName(), applyAuto.getWarehouseId(), applyAuto.getWarehouseName(), matr.getTemperature(), UtilCommon.getStr(matr.getBaseType(), "matr"));

            List<ApplyAuto> items = groupApplyAuto.get(deptAutoApplyKey);
            if (items == null) {
                items = Lists.newArrayList();
            }
            items.add(applyAuto);
            groupApplyAuto.put(deptAutoApplyKey, items);
        }
        List<Order> orders = new ArrayList<>();
        for (DeptAutoApplyKey deptAutoApplyKey : groupApplyAuto.keySet()) {
            Order order = convertAutoApplyToOrder(deptAutoApplyKey, groupApplyAuto.get(deptAutoApplyKey));
            orders.add(order);

        }

        return orders;
    }




    @Override
    public String fillQty(List<ApplyAuto> applyAutos) {

        List<ApplyAuto> addList = new ArrayList<>();
        //先过滤一下作废的数据和
        applyAutos = this.list(Wrappers.<ApplyAuto>query().in("id", applyAutos.stream().map(ApplyAuto::getId).collect(Collectors.toList())));

        if (applyAutos == null || applyAutos.size() == 0) {
            throw new BusinessException("该需求已作废，不能进行响应操作,请重新刷新界面！");
        }
        for (ApplyAuto applyAuto : applyAutos) {
//                            只更新对应字段
            ApplyAuto applyAutoNew = new ApplyAuto();
            applyAutoNew.setBillPackageUnit(applyAuto.getRequiredUnit());
            applyAutoNew.setBillPackageRate(applyAuto.getRequiredRate());
            double billPackageQty = (applyAuto.getSkuQtyApply() - applyAuto.getOnWayQty()) < 0 ? 0D : (applyAuto.getSkuQtyApply() - applyAuto.getOnWayQty())/applyAuto.getRequiredRate();
            applyAutoNew.setBillPackageQty(Math.ceil(billPackageQty));
            applyAutoNew.setId(applyAuto.getId());
            addList.add(applyAutoNew);
        }
        if (!addList.isEmpty()) {
            this.updateBatchById(addList);
        }
        return String.format("本次响应【%s】条明细,开单【%s】条明细", applyAutos.size(), addList.size());
    }


    private Order convertAutoApplyToOrder(DeptAutoApplyKey deptAutoApplyKey, List<ApplyAuto> applyAutosItem) {

        String supplierId = deptAutoApplyKey.supplierId;
        Supplier supplier = supplierMapper.selectById(supplierId);
        if (supplier == null) {
            throw new BusinessException("转换采购订单失败");
        }

        // 订单金额求和

        String orderCode = serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.PURCHASE_ORDER_KEY);
        Double orderAmount = 0.00;
        Order order = new Order();
        order.setBusKey(orderCode)
                .setSupplierId(supplierId)
                .setSupplierName(supplier.getName())
                .setBusDate(new Date())
                .setBusUser(UserUtils.currentUser().getName())
                .setBusUserCode(UserUtils.currentUser().getWorkNo())
                .setDeptIdDemand(deptAutoApplyKey.getApplyDeptId())
                .setDeptNameDemand(deptAutoApplyKey.getApplyDeptName())
                .setFlagOmoc(deptAutoApplyKey.getFlagOmoc())
                .setPoType(deptAutoApplyKey.getFlagConsignment() ? PoType.CONSIGNMENT.getValue() : PoType.BUY.getValue())
                .setDateLates(DateUtils.addDays(new Date(), 3))
                .setAmount(0.00)
                .setFlagPushed(false)
                .setWarehouseId(deptAutoApplyKey.getWarehouseId())
                .setWarehouseName(deptAutoApplyKey.getWarehouseName())
                .setRemark("自动生成采购订单").setPurchaseType(deptAutoApplyKey.getBaseType()).setTemperature(UtilCommon.getStr(deptAutoApplyKey.getTemperature(), "无"))
                .setRefTable("dept_apply_auto")
        ;
        orderMapper.insert(order);

        for (ApplyAuto applyAuto : applyAutosItem) {
            OrderItem orderItem = new OrderItem();
            Matr matr = matrMapper.selectById(applyAuto.getMatrId());
            MatrUnit matrUnit = null;

            matrUnit = matrUnitMapper.selectOne(new QueryWrapper<MatrUnit>().eq("matr_id", matr.getId())
                    .eq("rate", applyAuto.getRequiredRate()).eq("unit", applyAuto.getRequiredUnit()));
            if (matrUnit == null) {
                matrUnit = matrUnitMapper.selectOne(new QueryWrapper<MatrUnit>().eq("matr_id", matr.getId())
                        .eq("flag_base", "1").last("LIMIT 1"));
            }
            orderItem.setOrderId(order.getId())
                    .setRefId(applyAuto.getId())
                    .setMatrId(applyAuto.getMatrId())
                    .setMatrName(applyAuto.getMatrName())
                    .setMatrSpec(applyAuto.getMatrSpec())
                    .setMatrModel(applyAuto.getMatrModel())
                    .setPackageUnit(matrUnit.getUnit())
                    .setPackageQty(Math.ceil(applyAuto.getSkuQtyApply() / matrUnit.getRate()))
                    .setPackageRate(matrUnit.getRate())
                    .setSkuUnit(matr.getSkuUnit())
                    .setSkuQty(matrUnit.getRate() * orderItem.getPackageQty())
                    .setSkuPrice(matr.getSkuPrice())
                    .setAmount(matrUnit.getRate() * orderItem.getPackageQty() * matr.getSkuPrice())
                    .setStatusSupplier(0);

            orderItemMapper.insert(orderItem);
            applyAuto.setGmtResponse(LocalDateTime.now()).setRefOrderId(order.getId());
            orderAmount += orderItem.getAmount();
            super.updateCascadeById(applyAuto);
        }
        order.setAmount(orderAmount);

        orderMapper.updateById(order);
        return order;
    }

    @Override
    public List<Demand> toDemand(List<ApplyAuto> applyAutos) {
        //先过滤一下作废的数据和
        applyAutos = this.list(Wrappers.<ApplyAuto>query().in("id", applyAutos.stream().map(ApplyAuto::getId).collect(Collectors.toList())));

        if (applyAutos == null || applyAutos.size() == 0) {
            throw new BusinessException("该需求已作废，不能进行响应操作,请重新刷新界面！");
        }

        //开单单位不能为空 || 数量不能小于1
        applyAutos.stream().filter(item -> StringUtils.isBlank(item.getBillPackageUnit()))
                .findFirst().ifPresent(item -> {
            throw new BusinessException("耗材【%s】品规【%s】的开单单位不能为空", item.getMatrName(), item.getMatrSpec());
        });

        applyAutos.stream().filter(item -> item.getBillPackageQty() == 0d)
                .findFirst().ifPresent(item -> {
            throw new BusinessException("耗材【%s】品规【%s】的开单数量不能为0", item.getMatrName(), item.getMatrSpec());
        });

        List<Demand> demandList = new ArrayList<>();
        Map<String, List<ApplyAuto>> listMap = applyAutos.stream().collect(Collectors.groupingBy(ApplyAuto::getDeptId));
        listMap.keySet().forEach(deptId->{
            List<ApplyAuto> applyAutosDept = listMap.get(deptId);
            Demand demand = convertApplyToDemand(applyAutosDept,deptId);
            demandList.add(demand);
        });
        return demandList;
    }


    /**
     * 将自动请领转换为需求
     */
    private Demand convertApplyToDemand(List<ApplyAuto> applyAutos,String deptId) {
        Dept dept = (Dept) CacheUtils.get(CacheUtils.BASE_DEPT, deptId);
        if (dept == null) {
            throw new BusinessException("校验失败！<br>科室【%s】为空,请重新维护科室", applyAutos.get(0).getDeptName());
        }
        Demand demand = new Demand();
        List<ApplyAuto> refAutoList = new ArrayList<>();
        double amount = 0d;
         demand.setBusKey(null)
                .setRefTable(GlobalConsts.AUTO_REF_TABLE_SAFE)
                .setDeptId(dept.getId())
                .setDeptName(dept.getName())
                .setDateLates(DateUtils.format(DateUtils.addDays(new Date(), 3), "yyyy-MM-dd"))
                .setApplyWarehouseId(applyAutos.get(0).getWarehouseId())
                .setApplyWarehouseName(applyAutos.get(0).getWarehouseName())
                .setAmount(0D)
                .setBusDate(new Date())
                .setBusUser(UserUtils.currentUser().getCode())
                .setBusUserCode(UserUtils.currentUser().getName())
                .setFlowStatus(GlobalConsts.FLOW_SUBMIT_VALUE)
                .setId(null);

        if (!demandService.saveOrUpdate(demand)) {
            throw new BusinessException("转换需求失败");
        }
        List<DemandItem> demandItems = Lists.newArrayListWithCapacity(applyAutos.size());
        for (ApplyAuto applyAuto : applyAutos) {
            DemandItem demandItem = new DemandItem();
            BeanUtils.copyProperties(applyAuto, demandItem);
            demandItem.setDemandId(demand.getId()).setApplyAutoId(applyAuto.getId())
                    .setPackageRate(applyAuto.getBillPackageRate())
                    .setPackageUnit(applyAuto.getBillPackageUnit())
                    .setPackageQty(applyAuto.getBillPackageQty())
                    .setSkuQty(applyAuto.getBillPackageQty() * applyAuto.getBillPackageRate())
                    .setApplyAutoId(applyAuto.getId())
                    .setId(null);
            demandItem.setAmount(demandItem.getSkuQty() * demandItem.getSkuPrice());
            amount += demandItem.getSkuQty() * demandItem.getSkuPrice();
            demandItems.add(demandItem);
            ApplyAuto applyAutoNew = new ApplyAuto();
            applyAutoNew.setGmtResponse(LocalDateTime.now())
                    .setRefOrderId(demand.getId())
                    .setBusKey(demand.getBusKey())
                    .setBillPackageQty(0D)
                    .setId(applyAuto.getId());
            refAutoList.add(applyAutoNew);
        }
        demandItemService.saveBatch(demandItems);
        demand.setAmount(amount);
        demandService.updateById(demand);
//        回写关联关系
        this.updateBatchById(refAutoList);
        return demand;
    }

    @Override
    public Page<?> page(QueryContext context) {
        Page<Map> page = (Page<Map>) super.page(context);
        if (page.getRecords() != null && page.getRecords().size() > 0) {
            List<String> matrIdList = page.getRecords().stream().map(map -> String.valueOf(map.get("matrId"))).distinct().collect(Collectors.toList());
            List<String> warehouseIdList = page.getRecords().stream().map(map -> String.valueOf(map.get("warehouseId"))).distinct().collect(Collectors.toList());
            QueryWrapper queryWrapper = Wrappers.<Stock>query().in("matr_id", matrIdList).in("warehouse_id", warehouseIdList);

            List<StockGroupWarehouseMatrDTO> stockGroupWarehouseMatrDTOS = stockMapper.getListGroupByMatr(queryWrapper, null);

            List<String> msgArr = new ArrayList<>();
            for (Map map : page.getRecords()) {

                //实时库存包装列表
                if (stockGroupWarehouseMatrDTOS != null && stockGroupWarehouseMatrDTOS.size() > 0) {
                    List<StockGroupWarehouseMatrDTO> findList = stockGroupWarehouseMatrDTOS.stream()
                            .filter(stockGroupWarehouseMatrDTO -> (String.valueOf(map.get("matrId"))).equals(stockGroupWarehouseMatrDTO.getMatrId()) && (String.valueOf(map.get("warehouseId"))).equals(stockGroupWarehouseMatrDTO.getWarehouseId()))
                            .collect(Collectors.toList());
                    if (findList != null && findList.size() > 0) {
                        double skuStockQty = 0D;
                        msgArr.clear();
                        for (StockGroupWarehouseMatrDTO stockGroupWarehouseMatrDTO : findList) {
                            msgArr.add(UtilNum.trimZero(stockGroupWarehouseMatrDTO.getPackageQtyUse()) + stockGroupWarehouseMatrDTO.getPackageUnit());
                            skuStockQty += stockGroupWarehouseMatrDTO.getSkuQtyUse();
                        }
                        map.put("stockMsg", StringUtils.join(msgArr, "\n"));
                        map.put("skuQtyStock", skuStockQty);
                        map.put("stockList", findList);
                        double skuQtyApply = Double.parseDouble(String.valueOf(map.get("skuQtyApply")));
                        if (skuStockQty >= skuQtyApply) {
                            map.put("stockStatus", 0);
                        }
                        if (skuStockQty < skuQtyApply) {
                            map.put("stockStatus", 1);
                        }
                    } else {
                        map.put("stockMsg", "无库存");
                        map.put("stockStatus", -1);
                    }
                } else {
                    map.put("stockMsg", "无库存");
                    map.put("stockStatus", -1);
                }
            }
        }
        return page;
    }
}
